package P1线性结构;

import java.util.Arrays;
import java.util.Iterator;
import java.util.Objects;

//底层由顺序表实现的双端队列（同时具备栈与队列的功能）
public class ArrayDeque<E> implements Deque<E>, Iterable<E> {
    private static final int DEAFULT_CAPACITY = 10;
    private E[] data;
    private int size;
    private int front;  //队首指针
    private int rear;   //队尾指针

    public ArrayDeque() {
        data = (E[]) new Object[DEAFULT_CAPACITY + 1];
        front = 0;
        rear = 0;
        size = 0;
    }

    @Override
    public void addFirst(E element) {
        if (element == null) {
            throw new IllegalArgumentException();
        }
        if ((rear + 1) % data.length == front) {
            resize(data.length * 2 - 1);
        }
        front = (front - 1 + data.length) % data.length;
        data[front] = element;
        size++;
    }

    private void resize(int newLength) {
        E[] newData = (E[]) new Object[newLength];
        int index = 0;
        for (int i = front; i != rear; i = (i + 1) % data.length) {
            newData[index++] = data[i];
        }
        data = newData;
        front = 0;
        rear = index;
    }

    @Override
    public void addLast(E element) {
        if (element == null) {
            throw new IllegalArgumentException();
        }
        if ((rear + 1) % data.length == front) {
            resize(data.length * 2 - 1);
        }
        data[rear] = element;
        rear = (rear + 1) % data.length;
        size++;
    }

    @Override
    public E removeFirst() {
        if (isEmpty()) {
            throw new IllegalArgumentException("deque is empty");
        }
        E ret = data[front];
        front = (front + 1) % data.length;
        size--;
        if (size == (data.length - 1) / 4 && data.length - 1 > DEAFULT_CAPACITY) {
            resize(data.length / 2 + 1);
        }
        return ret;
    }

    @Override
    public E removeLast() {
        if (isEmpty()) {
            throw new IllegalArgumentException("deque is empty");
        }
        rear = (rear - 1 + data.length) % data.length;
        E ret = data[rear];
        size--;
        if (size == (data.length - 1) / 4 && data.length - 1 > DEAFULT_CAPACITY) {
            resize(data.length / 2 + 1);
        }
        return ret;
    }

    @Override
    public E getFirst() {
        if (isEmpty()) {
            throw new IllegalArgumentException("deque is empty");
        }
        return data[front];
    }

    @Override
    public E getLast() {
        if (isEmpty()) {
            throw new IllegalArgumentException("deque is empty");
        }
        return data[(rear - 1 + data.length) % data.length];
    }

    @Override
    public int size() {
        return size;
    }

    @Override
    public boolean isEmpty() {
        return size == 0 && front == rear;
    }

    @Override
    public void clear() {
        data = (E[]) new Object[DEAFULT_CAPACITY + 1];
        size = 0;
        front = 0;
        rear = 0;
    }

    @Override
    public void push(E element) {   //进栈
        addLast(element);
    }

    @Override
    public E pop() {    //弹栈
        return removeLast();
    }

    @Override
    public E peek() {   //查看栈顶
        return getLast();
    }

    @Override
    public void offer(E element) {  //入队
        addLast(element);
    }

    @Override
    public E poll() {   //出队
        return removeFirst();
    }

    @Override
    public E element() {    //查看队首
        return getFirst();
    }

    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder();
        sb.append('[');
        if (isEmpty()) {
            sb.append(']');
        } else {
            for (int i = front; i != rear; i = (i + 1) % data.length) {
                sb.append(data[i]);
                if ((i + 1) % data.length == rear) {
                    sb.append(']');
                } else {
                    sb.append(',');
                    sb.append(' ');
                }
            }
        }
        sb.append(' ');
        sb.append(size);
        sb.append('/');
        sb.append(data.length - 1);
        return sb.toString();
    }

    @Override
    public boolean equals(Object obj) {
        if (obj == null) {
            return false;
        }
        if (obj == this) {
            return true;
        }
        if (obj instanceof ArrayDeque) {
            ArrayDeque<E> other = (ArrayDeque<E>) obj;
            if (size == other.size) {
                E[] v1 = data;
                E[] v2 = other.data;
                int p1 = front;
                int p2 = other.front;
                while (p1 != rear) {
                    if (!v1[p1].equals(v2[p2])) {
                        return false;
                    }
                    p1 = (p1 + 1) % v1.length;
                    p2 = (p2 + 1) % v2.length;
                }
                return true;
            }
        }
        return false;
    }


    @Override
    public Iterator<E> iterator() {
        return new ArrayDequeIterator();
    }

    private class ArrayDequeIterator implements Iterator<E> {
        private int cur = front;

        @Override
        public boolean hasNext() {
            return cur != rear;
        }

        @Override
        public E next() {
            E ret = data[cur];
            cur = (cur + 1) % data.length;
            return ret;
        }
    }
}